﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace Hukee.ExcelHelper
{

    /// <summary>
    /// ICollection 输出Excel数据的扩展方法
    /// </summary>
    public static class CollectionToExcelExtensions
    {
        /// <summary>
        /// 列表转换成Excel的sheet分页数据 *列表所属类 必须有[ExcelColumn]特性修饰过
        /// </summary>
        /// <typeparam name="T">必须有[ExcelColumn]特性修饰过的类</typeparam>
        /// <param name="collection"></param>
        /// <returns></returns>
        public static ExcelSheetData ToExcelSheetData<T>(this ICollection<T> collection) where T : class
        {
            return GetExcelArrayByList(collection);
        }

        /// <summary>
        /// 获得Excel的Sheet数据
        /// </summary>
        /// <typeparam name="T">class对象必须要有ExcelColumn特性修饰</typeparam>
        /// <param name="list">转换数据列表</param>
        /// <returns>返回二维字符串数组</returns>
        private static ExcelSheetData GetExcelArrayByList<T>(ICollection<T> list) where T : class
        {
            var objType = typeof(T);

            List<ExcelColumn> excelColumnList = new List<ExcelColumn>();
            var aimProps = new List<PropertyInfo>();
            var propExcelDic = new Dictionary<PropertyInfo, ExcelColumn>();
            var excelDic = new Dictionary<ExcelColumn, int>();
            var propChangerDic = new Dictionary<PropertyInfo, ExcelValueChanger[]>();
            var propStrFormateDic = new Dictionary<PropertyInfo, ExcelStringFormate>();
            var propFontFormateDic = new Dictionary<ExcelColumn, ExcelStyle[]>();
            //取属性上的自定义特性
            foreach (PropertyInfo propInfo in objType.GetProperties())
            {
                var objAttrs = propInfo.GetCustomAttribute(typeof(ExcelColumn), true);
                if (objAttrs != null && objAttrs is ExcelColumn attr)
                {
                    excelColumnList.Add(attr); //列名
                    propExcelDic.Add(propInfo, attr);
                }
                else continue;
                // 转换特性设置
                var changerAttrs = propInfo.GetCustomAttributes(typeof(ExcelValueChanger), true);
                if (changerAttrs != null && changerAttrs.Length > 0 && (changerAttrs is ExcelValueChanger[] changeAttr))
                {
                    propChangerDic.Add(propInfo, changeAttr);
                }

                // 字符串格式化特性设置
                var strFormateAttrs = propInfo.GetCustomAttribute(typeof(ExcelStringFormate), true);
                if (strFormateAttrs != null && (strFormateAttrs is ExcelStringFormate strAttr))
                {
                    propStrFormateDic.Add(propInfo, strAttr);
                }

                // 字体样式设置
                var fontFormateAttrs = propInfo.GetCustomAttributes(typeof(ExcelStyle), true);
                if (fontFormateAttrs != null && fontFormateAttrs.Length > 0 && (fontFormateAttrs is ExcelStyle[] fontAttr))
                {
                    propFontFormateDic.Add(attr, fontAttr);
                }

                aimProps.Add(propInfo);
            }

            if (aimProps.Count == 0) throw new Exception("该类完全没有被[ExcelColumn]特性标识过！");

            //从小到大排序
            excelColumnList.Sort((left, right) =>
            {
                if (left.CloumnNumber > right.CloumnNumber)
                    return 1;
                else if (left.CloumnNumber == right.CloumnNumber)
                    return 0;
                else
                    return -1;
            });

            //初始化设置 excel二维数组
            object[,] excel = null;
            var ExcelForntList = new Dictionary<int, ExcelStyle[]>();
            if (excelColumnList.Count > 0)
            {
                excel = new object[list.Count + 1, excelColumnList.Count];
                // 标题行
                for (int i = 0; i < excelColumnList.Count; i++)
                {
                    var item = excelColumnList[i];
                    excelDic.Add(item, i);
                    excel[0, i] = item.ColumnName;
                    if (propFontFormateDic.ContainsKey(item)) ExcelForntList.Add(i, propFontFormateDic[item]);
                }
            }

            int x = 1;
            foreach (var v in list)
            {
                foreach (var pro in aimProps)
                {
                    if (propExcelDic.ContainsKey(pro))//如果该属性字段有标记要做为Excel输出
                    {
                        var attr = propExcelDic[pro];
                        if (excelDic.ContainsKey(attr))//获取所在列数
                        {
                            int y = excelDic[attr];
                            var proValue = pro.GetValue(v) ?? string.Empty;
                            if (propChangerDic.ContainsKey(pro))
                            {
                                var changer = propChangerDic[pro];
                                var matchValue = changer.FirstOrDefault(s => s.Condition.Equals(proValue));
                                if (matchValue != null)
                                {
                                    excel[x, y] = matchValue.ChangeValue;
                                }
                                else excel[x, y] = proValue.ToString();
                            }
                            if (propStrFormateDic.ContainsKey(pro))
                            {
                                //if (proValue is float floatValue)
                                //{
                                //    excel[x, y] = floatValue.ToString(propStrFormateDic[pro].Formate);
                                //}
                                //else if (proValue is double doubleValue)
                                //{
                                //    excel[x, y] = doubleValue.ToString(propStrFormateDic[pro].Formate);
                                //}
                                //else if (proValue is decimal decimalValue)
                                //{
                                //    excel[x, y] = decimalValue.ToString(propStrFormateDic[pro].Formate);
                                //}
                                //else excel[x, y] = proValue.ToString();
                                //数字保留多少位暂时没改
                                if (proValue is DateTime dateValue)
                                {
                                    excel[x, y] = dateValue.ToString(propStrFormateDic[pro].Formate);
                                }
                                else excel[x, y] = proValue;
                            }
                            else excel[x, y] = proValue.ToString();
                        }
                    }
                }
                x++;
            }

            var sheetAttr = objType.GetCustomAttribute(typeof(ExcelSheet), true);
            var sheetName = string.Empty;
            if (sheetAttr != null && sheetAttr is ExcelSheet excelSheet)
            {
                sheetName = excelSheet.SheetName;
            }

            var result = new ExcelSheetData(sheetName, excel, ExcelForntList);

            var fileNameAttr = objType.GetCustomAttribute(typeof(ExcelFile), true);
            if (fileNameAttr != null && fileNameAttr is ExcelFile excelFile)
            {
                if(!string.IsNullOrWhiteSpace(excelFile.FileName))
                    result.ExcelFileName = excelFile.FileName;
            }
            return result;
        }

    }
}
